package com.easy.framework.database.service;


import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.easy.framework.common.model.BaseQuery;
import com.easy.framework.common.utils.ConvertUtil;
import com.easy.framework.common.utils.Func;
import com.easy.framework.database.exception.WhereException;
import com.easy.framework.database.page.PageUtil;
import com.easy.framework.database.page.Pagination;
import com.easy.framework.database.utils.QueryUtil;
import com.github.pagehelper.ISelect;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 扩展 IService 接口
 *
 * @author Yang Huijing
 */
public interface IService<T, Q extends BaseQuery> extends com.baomidou.mybatisplus.extension.service.IService<T> {


    /**
     * 获取 LambdaQueryWrapper<T> 对象
     *
     * @return
     */
    default LambdaQueryWrapper<T> lambdaQueryWrapper() {
        return Wrappers.<T>lambdaQuery();
    }

    /**
     * 获取 LambdaQueryWrapper<T> 对象
     *
     * @param q 条件对象
     * @return
     */
    default LambdaQueryWrapper<T> lambdaQuery(Q q) {
        return QueryUtil.lambdaQuery(q, getEntityClass());
    }

    /**
     * 获取 LambdaQueryWrapper<T> 对象
     *
     * @param q             条件对象
     * @param requiredWhere 必须存在条件
     * @return
     */
    default LambdaQueryWrapper<T> lambdaQuery(Q q, boolean requiredWhere) {
        LambdaQueryWrapper<T> lambdaQueryWrapper = QueryUtil.lambdaQuery(q, getEntityClass());
        if (requiredWhere && (null == lambdaQueryWrapper || lambdaQueryWrapper.isEmptyOfWhere())) {
            throw new WhereException("Where is empty");
        }
        return lambdaQueryWrapper;
    }

    /**
     * 获取 Optional<LambdaQueryWrapper<T>> 对象
     *
     * @param q 条件对象
     * @return
     */
    default Optional<LambdaQueryWrapper<T>> lambdaQueryOptional(Q q) {
        return QueryUtil.lambdaQueryOptional(q, getEntityClass());
    }

    /**
     * 删除数据
     *
     * @param q 指定条件
     * @return
     */
    default boolean remove(Q q) {
        return SqlHelper.retBool(this.getBaseMapper().delete(lambdaQuery(q, true)));
    }

    /**
     * 更新数据
     *
     * @param entity 更新数据
     * @param q      指定条件
     * @return
     */
    default boolean update(T entity, Q q) {
        return SqlHelper.retBool(this.getBaseMapper().update(entity, lambdaQuery(q, true)));
    }

    /**
     * 查询列表数据
     *
     * @param q 指定条件
     * @return
     */
    default List<T> list(Q q) {
        return this.list(lambdaQuery(q));
    }

    /**
     * 获取一条数据
     *
     * @param q 指定条件
     * @return
     */
    default T get(Q q) {
        return this.getOne(lambdaQuery(q, true));
    }


    /**
     * 获取一条数据
     *
     * @param q      指定条件
     * @param single 只有一条数据 （true:只有一条数据，false:有多条数据取第一条)
     * @return
     */
    default T get(Q q, boolean single) {
        return this.getOne(lambdaQuery(q, true), single);
    }


    /**
     * 分页查询
     *
     * @param pageNum    --当前页码
     * @param pageSize   --每页数据条数
     * @param reasonable --分页合理化
     * @param select     --数据查询接口
     * @return --返回分页数据
     */
    default Pagination<T> page(Integer pageNum, Integer pageSize, boolean reasonable, ISelect select) {
        return PageUtil.page(pageNum, pageSize, reasonable, select);
    }

    /**
     * 分页查询
     *
     * @param pageNum  --当前页码
     * @param pageSize --每页数据条数
     * @param select   --数据查询接口
     * @return --返回分页数据
     */
    default Pagination<T> page(Integer pageNum, Integer pageSize, ISelect select) {
        return PageUtil.page(pageNum, pageSize, true, select);
    }

    /**
     * 分页查询
     *
     * @param query  --查询对象
     * @param select --数据查询接口
     * @return --返回分页数据
     */
    default Pagination<T> page(Q query, ISelect select) {
        return PageUtil.page(query, select);
    }

    /**
     * 分页查询
     *
     * @param select --数据查询接口
     * @return --返回分页数据
     */
    default Pagination<T> page(ISelect select) {
        return PageUtil.page(select);
    }

    /**
     * 内存数据分页
     *
     * @param pageNum  --当前页码
     * @param pageSize --每页数据条数
     * @param list     --数据列表
     * @return --返回分页数据
     */
    default Pagination<T> page(Integer pageNum, Integer pageSize, List<T> list) {
        return PageUtil.page(pageNum, pageSize, list);
    }

    /**
     * 分页查询
     *
     * @param q 指定条件
     * @return
     */
    default Pagination<T> page(Q q) {
        return page(q, () -> list(q));
    }

    /**
     * 分页查询
     *
     * @param pageNum  页码
     * @param pageSize 每页数据条数
     * @param wrapper  指定条件
     * @return
     */
    default Pagination<T> page(Integer pageNum, Integer pageSize, Wrapper<T> wrapper) {
        return page(pageNum, pageSize, () -> list(wrapper));
    }

    /**
     * 检查是否存在
     *
     * @param wrapper    指定条件
     * @param idFunction 指定排除字段
     * @param id         指定排除字段值
     * @return
     */
    default boolean exists(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> idFunction, Object id) {
        if (wrapper.isEmptyOfWhere()) {
            throw new WhereException("Where is empty");
        }
        T t = getOne(wrapper, false);
        if (Func.isNotEmpty(t) && ((null == idFunction || null == id) || (
                (id instanceof Long && !idFunction.apply(t).equals(ConvertUtil.toLong(id)))
                        || (id instanceof String && !idFunction.apply(t).equals(ConvertUtil.toStr(id)))
                        || (id instanceof Integer && !idFunction.apply(t).equals(ConvertUtil.toInt(id)))
        ))) {
            return true;
        }
        return false;
    }

    /**
     * 检查是否存在
     *
     * @param function   指定检查的字段
     * @param value      指定检查的字段值
     * @param idFunction 指定排除字段
     * @param id         指定排除字段值
     * @return
     */
    default boolean exists(SFunction<T, ?> function, Object value, SFunction<T, ?> idFunction, Object id) {
        return exists(lambdaQueryWrapper().eq(function, value), idFunction, id);
    }

    /**
     * 检查是否存在
     *
     * @param function 指定检查的字段
     * @param value    指定检查的字段值
     * @return
     */
    default boolean exists(SFunction<T, ?> function, Object value) {
        return exists(lambdaQueryWrapper().eq(function, value), null, null);
    }

    /**
     * 获取指定字段的列表
     *
     * @param function 指定字段
     * @return
     */
    default <DT> List<DT> getValueList(Q q, SFunction<T, DT> function) {
        return Optional.ofNullable(list(q)).orElse(Collections.emptyList()).stream().map(function).collect(Collectors.toList());
    }
}
